package com.seadragon.app.ksr.dao.jpa;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;

import org.springframework.stereotype.Repository;

import com.seadragon.app.ksr.dao.ReviewDao;
import com.seadragon.app.ksr.model.Customer;
import com.seadragon.app.ksr.model.Office;
import com.seadragon.app.ksr.model.Review;

@Repository("reviewDao")
public class ReviewDaoJpaImpl extends AbstractJpaDao implements ReviewDao {
	@Override
	public Review save(Review review){
		if(review.getId() != 0){
			return entityManager.merge(review);
		}else{
			entityManager.persist(review);
		}
		return review;
	}

	@Override
	public List<Review> findByOffice(Office office) {
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Review> cq = cb.createQuery(Review.class);
		Root<Review> root = cq.from(Review.class);
		cq.select(root);
		cq.where(cb.equal(root.get("office"), office));
		return entityManager.createQuery(cq).getResultList();
	}

	@Override
	public List<Review> findByOfficeAndReview(Office office, int reviewRating) {
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Review> cq = cb.createQuery(Review.class);
		Root<Review> root = cq.from(Review.class);
		cq.select(root);
		cq.where(cb.and(cb.equal(root.get("office"), office), cb.equal(root.get("rating"), reviewRating)));
		return entityManager.createQuery(cq).getResultList();
	}

	@Override
	public long count(Office office){
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Long> cq = cb.createQuery(Long.class);
		Root<Review> root = cq.from(Review.class);
		cq.select(cb.count(root));
		cq.where(cb.equal(root.get("office"), office));
		return entityManager.createQuery(cq).getSingleResult();
	}

	@Override
	public List<Review> findByCustomer(Customer customer) {
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Review> cq = cb.createQuery(Review.class);
		Root<Review> root = cq.from(Review.class);
		cq.select(root);
		cq.where(cb.equal(root.get("customer"), customer));
		return entityManager.createQuery(cq).getResultList();
	}

	@Override
	public List<Review> findByCustomerAndReview(Customer customer, int reviewRating) {
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Review> cq = cb.createQuery(Review.class);
		Root<Review> root = cq.from(Review.class);
		cq.select(root);
		cq.where(cb.and(cb.equal(root.get("customer"), customer), cb.equal(root.get("rating"), reviewRating)));
		return entityManager.createQuery(cq).getResultList();
	}
	
	@Override
	public Map<Integer, Long> getStatsByOffice(Office office) {
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Object[]> q = cb.createQuery(Object[].class);
		Root<Review> c = q.from(Review.class);
		q.select(cb.array(c.get("rating"), cb.count(c.get("rating"))));
		q.where(cb.equal(c.get("office"), office));
		q.groupBy(c.get("rating"));
		List<Object[]> result = entityManager.createQuery(q).getResultList();
		Map<Integer, Long> map = new HashMap<Integer, Long>();
		for(Object[] objs : result){
			map.put((Integer)objs[0], (Long)objs[1]);
		}
		return map;
		/**
		 * CriteriaQuery<Object[]> qdef = cb.createQuery(Object[].class);
		 * Root<Clerk> c = qdef.from(Clerk.class); Join<Clerk,Sale> s =
		 * c.join("sales", JoinType.LEFT); qdef.select(cb.array(c,
		 * cb.count(s))).groupBy(c);
		 */
	}
	
	public void update(Review review){
		if(review.getId() != 0){
			Review existedReview = entityManager.find(Review.class, review.getId());
			existedReview.setContent(review.getContent());
			existedReview.setRating(review.getRating());
			existedReview.setDateUpdated(new Date());
			existedReview.setTitle(review.getTitle());
			entityManager.merge(existedReview);
		}

	}

	@Override
	public List<Review> findAll(int offset, int pageSize) {
		CriteriaBuilder cb = entityManager.getCriteriaBuilder();
		CriteriaQuery<Review> cq = cb.createQuery(Review.class);
		Root<Review> root = cq.from(Review.class);
		cq.select(root);
		TypedQuery<Review> tq = entityManager.createQuery(cq);
		tq.setFirstResult(offset);
		tq.setMaxResults(pageSize);
		return tq.getResultList();
	}

}
